#include "audiowidget.h"

#include <QAudioDevice>
#include <QAudioOutput>
#include <QFile>
#include <QHBoxLayout>
#include <QLabel>
#include <QMediaCaptureSession>
#include <QMediaDevices>
#include <QMediaPlayer>
#include <QVector>
#include "utils/signalcenter.h"
#include "utils/util.h"

audioWidget::audioWidget(QWidget *parent)
    : QWidget{parent}
    , speakerDevice(new QComboBox())
    , checkSpeaker(new QPushButton(this))
    , checkMircrophone(new QPushButton(this))
    , mainVLayout(new QVBoxLayout(this))
    , microphoneDevice(new QComboBox())
    , VLayout(new QVBoxLayout())
    , VLayout2(new QVBoxLayout())
    , HLayout2(new QHBoxLayout())
    , HLayout3(new QHBoxLayout())
    , label1(new QLabel())
    , label2(new QLabel())
    , label3(new QLabel())
    , label4(new QLabel())
    , btnLevel(new QToolButton)
    , btnyinliang(new QToolButton)
    , btnInputLevel(new QToolButton())
    , btnInputYinliang(new QToolButton())
    , myPlayer(new MyAudioPlayer(this))
    , bilateralPlayer(new bilateralAudioPlay(this))
    , chooseOutputDeviceIndex(0)
    , chooseItputDeviceIndex(0)
    , sound(new CustomSlider(Qt::Horizontal, this))
    , sliderValue(0.5)
    , inputSoundSliderValue(0.5)
    , inputSound(new CustomSlider(Qt::Horizontal, this))
    , checkBox(new QCheckBox(this))
{
    mainVLayout->setObjectName("mainVLayout");
    mainVLayout->setContentsMargins(10, 10, 10, 10);
    mainVLayout->setSpacing(50);

    VLayout->setObjectName("VLayout");
    VLayout->setSpacing(10);

    QLabel *speaker = new QLabel();
    speaker->setObjectName("speaker");
    speaker->setText("扬声器");
    QFont font = speaker->font();
    setQFont(font, "Microsoft YaHei", 12, true);
    speaker->setFont(font);
    VLayout->addWidget(speaker);

    //顶一个水平布局，里面存放检测扬声器的按钮和comboBox
    QHBoxLayout *HLayout = new QHBoxLayout();
    HLayout->setObjectName("HLayout");
    HLayout->setSpacing(2);

    speakerDevice->setObjectName("speakerDevice");
    setComBox(speakerDevice);
    getAvailableAudioOutPutDevice();
    HLayout->addWidget(speakerDevice);

    //创建检测扬声器按钮
    setPushButton(checkSpeaker, "checkSpeaker", "    检测扬声器");
    HLayout->addWidget(checkSpeaker);
    VLayout->addLayout(HLayout);

    label1->setObjectName("label1");
    setLabelAndBtn(label1, btnLevel, "输出等级", ":/resources/speaker.png");
    HLayout2->setSpacing(2);
    HLayout2->addWidget(label1);
    HLayout2->addWidget(btnLevel);
    addProgressBar(SpeakerProBars, HLayout2);
    //第三个水平布局
    HLayout3->setSpacing(2);
    label2->setObjectName("label2");
    setLabelAndBtn(label2, btnyinliang, "输出音量", ":/resources/sound.png");
    setCustomSlider(sound, "sound");

    HLayout3->addWidget(label2);
    HLayout3->addWidget(btnyinliang);
    HLayout3->addWidget(sound);

    VLayout->addLayout(HLayout2);
    VLayout->addLayout(HLayout3);
    mainVLayout->addLayout(VLayout);

    //下面就是麦克风部分的了
    VLayout2->setObjectName("VLayout2");
    VLayout2->setSpacing(10);

    QLabel *microphone = new QLabel();
    microphone->setObjectName("microphone");
    microphone->setText("麦克风");
    QFont font2 = microphone->font();
    setQFont(font2, "Microsoft YaHei", 12, true);
    microphone->setFont(font2);
    VLayout2->addWidget(microphone);

    QHBoxLayout *HboxLayout = new QHBoxLayout();
    HboxLayout->setObjectName("HboxLayout");
    HboxLayout->setSpacing(2);

    //设置麦克风设备的combobox
    microphoneDevice->setObjectName("microphoneDevice");
    setComBox(microphoneDevice);
    getAvailableAudioIntputDevice();
    HboxLayout->addWidget(microphoneDevice);

    //创建检测扬声器按钮
    setPushButton(checkMircrophone, "checkMircrophone", "    检测麦克风");
    HboxLayout->addWidget(checkMircrophone);
    //垂直布局中，加水平布局
    VLayout2->addLayout(HboxLayout);

    //继续添加一个水平布局存放输入等级和processbar
    QHBoxLayout *HboxLayout2 = new QHBoxLayout();
    HboxLayout2->setObjectName("HboxLayout2");
    HboxLayout2->setSpacing(2);

    label3->setObjectName("label3");
    btnInputLevel->setObjectName("btnInputLevel");
    setLabelAndBtn(label3, btnInputLevel, "输入等级", ":/resources/mic.png");
    HboxLayout2->addWidget(label3);
    HboxLayout2->addWidget(btnInputLevel);
    addProgressBar(MircroPhoneProBars, HboxLayout2);

    //将HboxLayout2加入到第二个存放麦克风调试的垂直布局中
    VLayout2->addLayout(HboxLayout2);

    //接下来就是输入音量的，这其中包括了一个水平布局，一个label和一个显示图标的按钮和一个滑块
    QHBoxLayout *HboxLayout3 = new QHBoxLayout();
    HboxLayout3->setObjectName("HboxLayout3");
    HboxLayout3->setSpacing(2);
    label4->setObjectName("label3");
    btnInputYinliang->setObjectName("btnInputYinliang");
    setLabelAndBtn(label4, btnInputYinliang, "输入音量", ":/resources/speaker2.png");

    setCustomSlider(inputSound, "inputSound");
    inputSound->setEnabled(false);
    setDiffStatusCustomSlider(inputSound, false);
    HboxLayout3->addWidget(label4);
    HboxLayout3->addWidget(btnInputYinliang);
    HboxLayout3->addWidget(inputSound);
    VLayout2->addLayout(HboxLayout3);

    //还有一个按钮
    checkBox->setObjectName("checkBox");
    checkBox->setChecked(true);
    checkBox->setText("自动调整麦克风音量");
    VLayout2->addWidget(checkBox);

    QLabel *spaceLabel = new QLabel();
    spaceLabel->setMinimumSize(QSize(170, 300));
    spaceLabel->setMaximumSize(QSize(170, 300));
    VLayout2->addWidget(spaceLabel);

    mainVLayout->addLayout(VLayout2);

    connect(checkSpeaker, &QPushButton::clicked, this, &audioWidget::onCheckSpeakerButtonClicked);
    connect(speakerDevice,
            &QComboBox::currentIndexChanged,
            this,
            &audioWidget::onSpeakerDeviceChange);
    connect(&SignalCenter::instance(),
            &SignalCenter::audioDataComputeCompleted,
            this,
            &audioWidget::onAudioDataComputeComplete);
    connect(sound, &QSlider::sliderMoved, this, &audioWidget::onSliderMove);
    connect(&SignalCenter::instance(),
            &SignalCenter::clearProBarVolume,
            this,
            &audioWidget::onClearProBarVolume);

    //麦克风部分的槽函数连接
    connect(checkMircrophone,
            &QPushButton::clicked,
            this,
            &audioWidget::onCheckMircroPhoneButtonClicked);

    connect(microphoneDevice,
            &QComboBox::currentIndexChanged,
            this,
            &audioWidget::onMircroPhoneDeviceChange);

    connect(inputSound, &QSlider::sliderMoved, this, &audioWidget::onInputSoundSliderMove);

    connect(checkBox, &QCheckBox::toggled, this, &audioWidget::onCheckBoxToggle);

    connect(&SignalCenter::instance(),
            &SignalCenter::audioPlayFinshed,
            this,
            &audioWidget::onAudioPlayFinished);
}

audioWidget::~audioWidget() {}

void audioWidget::stopSpeaker()
{
    myPlayer->stopPlay();

    resetProgressBar(OUTPUTLEVEL);
}

void audioWidget::stopMircroPhone()
{
    bilateralPlayer->stop();
}

void audioWidget::getAvailableAudioOutPutDevice()
{
    outputDevicesDescription = myPlayer->getOutputDevicesDescription();
    for (auto &description : outputDevicesDescription) {
        speakerDevice->addItem(description);
    }
}

void audioWidget::getAvailableAudioIntputDevice()
{
    iutputDevicesDescription = bilateralPlayer->getIntputDevicesDescription();
    for (auto &description : iutputDevicesDescription) {
        microphoneDevice->addItem(description);
    }
}

void audioWidget::PlayAudio()
{
    myPlayer->chooseOutputDevice(chooseOutputDeviceIndex);
    myPlayer->startPlay();
    //audioPlayStart = true;
}

void audioWidget::startMircroPhone()
{
    bilateralPlayer->selectInputAudioDevice(chooseItputDeviceIndex);
    bilateralPlayer->start();
}

void audioWidget::addProgressBar(QVector<QProgressBar *> &probars, QHBoxLayout *HBoxLauout)
{
    for (uint8_t i = 0; i < 10; ++i) {
        QProgressBar *probar = new QProgressBar();
        QString commonProbarName = "probar%1";
        QString proBarName(commonProbarName.arg(i + 1));
        probar->setObjectName(proBarName);
        probar->setMaximumSize(QSize(40, 15));
        probar->setMinimumSize(QSize(40, 15));
        probar->setRange(0, 100);
        probar->setValue(0);
        probar->setStyleSheet(
            "QProgressBar { border: 1px solid gainsboro;border-radius:3px; margin: "
            "1px; background-color:gainsboro;}");
        probar->setTextVisible(false);
        probars.emplace_back(probar);
        HBoxLauout->addWidget(probar);
    }
}

void audioWidget::setCustomSlider(CustomSlider *slider, const QString &name)
{
    slider->setObjectName(name);
    slider->setRange(0, 100); //这是设置范围
    slider->setValue(50);     //这是设置初始值
    slider->setStyleSheet("QSlider::groove:horizontal{border: 1px solid gainsboro;"
                          "height:6px;background:gainsboro; border-radius:3px}"
                          "QSlider::sub-page:horizontal{background: qlineargradient(x1: 0, y1: 0, "
                          "x2: 1, y2: 0,stop: 0 #1F71D1, stop: 1 #1F71D1);"
                          " height:6px;border-radius:3px}"
                          "QSlider::handle:horizontal{background:white;border:1px solid "
                          "#cfcfcf;width: 8px;height:8px;border-radius: 4px; margin: -4px 0; }");
}

void audioWidget::setDiffStatusCustomSlider(CustomSlider *slider, bool enable)
{
    if (enable) {
        slider->setStyleSheet(
            "QSlider::groove:horizontal{border: 1px solid gainsboro;"
            "height:6px;background:gainsboro; border-radius:3px}"
            "QSlider::sub-page:horizontal{background: qlineargradient(x1: 0, y1: 0, "
            "x2: 1, y2: 0,stop: 0 #1F71D1, stop: 1 #1F71D1);"
            " height:6px;border-radius:3px}"
            "QSlider::handle:horizontal{background:white;border:1px solid "
            "#cfcfcf;width: 8px;height:8px;border-radius: 4px; margin: -4px 0; }");
    } else {
        slider->setStyleSheet(
            "QSlider::groove:horizontal{border: 1px solid gainsboro;"
            "height:6px;background:gainsboro; border-radius:3px}"
            "QSlider::sub-page:horizontal{background: qlineargradient(x1: 0, y1: 0, "
            "x2: 1, y2: 0,stop: 0 gainsboro, stop: 1 gainsboro);"
            " height:6px;border-radius:3px}"
            "QSlider::handle:horizontal{background:white;border:1px solid "
            "#cfcfcf;width: 8px;height:8px;border-radius: 4px; margin: -4px 0; }");
    }
}

void audioWidget::setLabelAndBtn(QLabel *label,
                                 QToolButton *btn,
                                 const QString &LabelText,
                                 const QString &iconUrl)
{
    label->setText(LabelText);
    QFont font = label->font();
    setQFont(font, "Microsoft YaHei", 9, false);
    // label1->setMinimumSize(QSize(50, 30));
    // label1->setMaximumSize(QSize(50, 30));
    label->setFont(font);
    label->setAlignment(Qt::AlignCenter);
    btn->setCheckable(false);
    btn->setIcon(QIcon(iconUrl));
    btn->setStyleSheet("QToolButton{border: none;} ");
}

void audioWidget::setComBox(QComboBox *combobox)
{
    combobox->setStyleSheet("QComboBox {"
                            "    border: 1px solid gray;" // 边框宽度和颜色
                            "    border-radius: 5px;"     // 圆角半径
                            "    padding: 1px 18px 1px 3px;" // 内边距，确保文本不与边框重叠
                            "    min-width: 150px;"          // 最小宽度
                            "}"
                            "QComboBox::drop-down {"
                            "subcontrol-position: padding;"
                            "subcontrol-position: top right;"
                            "width: 16px;"
                            "border: none; /* 尺边框 */"
                            "border-image: url(:/resources/down-arrow.png) ;"
                            "}");
}

void audioWidget::resetProgressBar(role r)
{
    if (r == OUTPUTLEVEL) {
        for (auto &processBar : SpeakerProBars) {
            processBar->setValue(0);
        }
    } else {
        for (auto &processBar : MircroPhoneProBars) {
            processBar->setValue(0);
        }
    }
}

void audioWidget::setPushButton(QPushButton *btn, const QString &objectName, const QString &text)
{
    btn->setObjectName(objectName);
    btn->setText(text);
    btn->setCheckable(true); //这是设置按钮具有可选中状态，分为选中和未选中
    btn->setMinimumSize(QSize(70, 20));
    btn->setMaximumSize(QSize(70, 20));
    QFont font = btn->font();
    setQFont(font, "Microsoft YaHei", 10, false);
    btn->setFont(font);
    btn->setStyleSheet("QPushButton{border:1px solid gray; border-radius: 5px; padding: "
                       "1px 18px 1px 3px;min-width: 80px; text-align:center}"
                       "QPushButton:hover{border:1px solid green;color:green}");
}

void audioWidget::onCheckSpeakerButtonClicked(bool checked)
{
    if (checked) {
        checkSpeaker->setText("    停止测试");
        qDebug() << "正在测试中";
        PlayAudio();
    } else {
        checkSpeaker->setText("    检测扬声器");
        qDebug() << "退出测试";
        // player->stop();
        stopSpeaker();
    }
}

void audioWidget::onCheckMircroPhoneButtonClicked(bool checked)
{
    if (checked) {
        checkMircrophone->setText("    停止测试");
        qDebug() << "正在测试中";
        //PlayAudio();
        startMircroPhone();
    } else {
        checkMircrophone->setText("    检测麦克风");
        qDebug() << "退出测试";
        // player->stop();
        //stopSpeaker();
        stopMircroPhone();
    }
}

void audioWidget::onSpeakerDeviceChange(int index)
{
    chooseOutputDeviceIndex = index;
}

void audioWidget::onMircroPhoneDeviceChange(int index)
{
    chooseItputDeviceIndex = index;
}

void audioWidget::onAudioDataComputeComplete(float value, role r)
{
    //value里面传的值就是dBFS，范围是0，100；
    //resetProgressBar();
    if (r == OUTPUTLEVEL) {
        float f = value * sliderValue;
        // 动态填充每个进度条
        for (int i = 0; i < 10; ++i) {
            float lowerBound = i * 10;       // 当前进度条的下界
            float upperBound = (i + 1) * 10; // 当前进度条的上界

            if (f > lowerBound) {
                float fillValue = 0.0;
                if (f > upperBound) {
                    fillValue = 100; // 完全填充
                } else {
                    fillValue = ((f - lowerBound) / 10.0) * 100; // 计算部分填充
                }
                SpeakerProBars[i]->setValue(static_cast<int>(fillValue)); // 动态填充
            }
        }
    } else {
        float f = value * inputSoundSliderValue;
        for (int i = 0; i < 10; ++i) {
            float lowerBound = i * 10;       // 当前进度条的下界
            float upperBound = (i + 1) * 10; // 当前进度条的上界

            if (f > lowerBound) {
                float fillValue = 0.0;
                if (f > upperBound) {
                    fillValue = 100; // 完全填充
                } else {
                    fillValue = ((f - lowerBound) / 10.0) * 100; // 计算部分填充
                }
                MircroPhoneProBars[i]->setValue(static_cast<int>(fillValue)); // 动态填充
            }
        }
    }

    //resetProgressBar();
}

void audioWidget::onSliderMove(int value)
{
    float volume = static_cast<float>(value) / 100;
    sliderValue = volume;
    //因为这里变了，因此我们就需要让音乐的播放也需要变，并且呢，图标也是需要变得
    if (value == 0) {
        btnyinliang->setIcon(QIcon(":/resources/mute.png"));
    } else {
        btnyinliang->setIcon(QIcon(":/resources/sound.png"));
    }

    //并且这里需要发送信号，来通知AudioSink来改变音量
    emit SignalCenter::instance().audioVolumeChange(volume);
}

void audioWidget::onClearProBarVolume(role r)
{
    resetProgressBar(r);
}

void audioWidget::onCheckBoxToggle(bool checked)
{
    inputSound->setEnabled(!checked);
    setDiffStatusCustomSlider(inputSound, !checked);
}

void audioWidget::onInputSoundSliderMove(int value)
{
    inputSoundSliderValue = static_cast<float>(value) / 100;
    if (value == 0) {
        btnInputYinliang->setIcon(QIcon(":/resources/speaker3.png"));
    } else {
        btnInputYinliang->setIcon(QIcon(":/resources/speaker2.png"));
    }

    emit SignalCenter::instance().intputAudioVolumeChange(inputSoundSliderValue);
}

void audioWidget::onAudioPlayFinished()
{
    myPlayer->replay();
}
